﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Collections;
//using ErrorElement = System.Collections.Generic.KeyValuePair<string, string>;

namespace DBS
{
	/// <summary>
	/// Для облегчённого формирования XML файла
	/// </summary>
	public class XMLExporter
	{
		private struct ExporterElement
		{
			public XmlNode Element;
			public string ErrorId;

		}
		/// <summary>
		/// Требование обязательности очередного атрибута
		/// </summary>
		public bool Required = false;
		private XmlDocument _doc;
		private Encoding _encoding;
		ExporterElement _currentElement;
		Stack<ExporterElement> _elementsHistory;
		List<string> _errors = new List<string>();

		public XMLExporter(Encoding encoding)
		{
			if (encoding == null) encoding = Encoding.GetEncoding(1251);
			_encoding = encoding;
			_doc = new XmlDocument();
			_currentElement.Element = _doc;
			_currentElement.ErrorId = "root";
			_elementsHistory = new Stack<ExporterElement>();
		}
		public void Write(string path)
		{
			using (XmlTextWriter writer = new XmlTextWriter(path, _encoding))
			{
				writer.WriteStartDocument();
				_doc.WriteTo(writer);
			}
		}
		public void ElementCreate(string name, string errorId)
		{
			if (_elementsHistory.Count <= 0 && _doc.DocumentElement != null) throw new Exception("Нельзя создать два корневых элемента.");
			XmlNode element = _doc.CreateElement(name);
			_currentElement.Element.AppendChild(element);
			_elementsHistory.Push(_currentElement);
			_currentElement.Element = element;
			_currentElement.ErrorId = errorId;
		}
		public void ElementClose(string name)
		{
			if (_elementsHistory.Count <= 0) throw new Exception("Нет элементов для закрытия.");
			if (_currentElement.Element.Name != name) throw new Exception("Закрывается не тот элемент.");
			_currentElement = _elementsHistory.Pop();
		}

		private void CreateAttribute(string name, string formatted, bool exist)
		{
			if (!exist || formatted == null || formatted.Length == 0)
				if (!Required)
					return;
				else
					AddError(name, "Нет данных по обязательному атрибуту");
			XmlAttribute attr = _doc.CreateAttribute(name);
			attr.Value = formatted;
			_currentElement.Element.Attributes.Append(attr);
		}
		private void AddError(string aName, string error)
		{
			_errors.Add(string.Format("{0}: Атрибут {1}: {2}", _currentElement.ErrorId, aName, error));
		}
		public List<string> Errors { get { return _errors; } }

		//Формирование значений
		public void ANumber(string name, int maxLen, object value)
		{
			bool exist = true;
			if (Convert.IsDBNull(value) || value == null) value = string.Empty;
			string str = value.ToString();
			if (str.Length > 0)
				str = string.Format(new System.Globalization.CultureInfo("en-US", false).NumberFormat, "{0:#0}", value);
			else
				exist = false;
			if (str.Length > 0 && str.Length > 7)
				AddError(name, "Превышена длина.");
			CreateAttribute(name, str, exist);
		}
		public void ACurrency(string name, object value)
		{
			bool exist = true;
			if (Convert.IsDBNull(value) || value == null) value = string.Empty;
			string str = value.ToString();
			if (str.Length > 0)
				str = string.Format(new System.Globalization.CultureInfo("en-US", false).NumberFormat, "{0:#0.00}", value);
			else
				exist = false;
			if (str.Length > 0 && str.Length > 21)
				AddError(name, "Превышена длина.");
			CreateAttribute(name, str, exist);
		}
		public void AText(string name, int minLen, int maxLen, object value)
		{
			bool exist = true;
			if (Convert.IsDBNull(value) || value == null) value = string.Empty;
			string str = value.ToString().Trim();
			exist = str.Length > 0;
			if (str.Length < minLen && str.Length > maxLen)
				AddError(name, "Некорректная длина.");
			CreateAttribute(name, str, exist);
		}
		public void ATextFix(string name, int len, object value)
		{
			AText(name, len, len, value);
		}
		public void ATextMax(string name, int len, object value)
		{
			AText(name, 0, len, value);
		}
		public void ADate(string name, object value)
		{
			bool exist = true;
			if (Convert.IsDBNull(value) || value == null) value = string.Empty;
			string str = value.ToString();
			if (str.Length > 0)
				str = string.Format("{0:dd.MM.yyyy}", value);
			else
				exist = false;
			CreateAttribute(name, str, exist);
		}

	}
}
